package com.itdct.onflow.system.common.aspect

import com.alibaba.fastjson2.JSON
import com.itdct.onflow.core.aspect.BaseControllerAspect
import com.itdct.onflow.core.config.OnflowConfig
import com.itdct.onflow.core.constant.CommonString
import com.itdct.onflow.core.constant.ReturnCode
import com.itdct.onflow.core.context.BaseContext
import com.itdct.onflow.core.context.ContextHolder
import com.itdct.onflow.core.dto.BaseLoginDTO
import com.itdct.onflow.core.exception.CommonException
import com.itdct.onflow.core.extend.insertEx
import com.itdct.onflow.core.util.KBeanCopyUtil
import com.itdct.onflow.core.util.RedisReentrantLock
import com.itdct.onflow.core.util.RedisUtil
import com.itdct.onflow.system.account.constant.SysAccountRedisKey
import com.itdct.onflow.system.account.entity.SysAccountEntity
import com.itdct.onflow.system.api.constant.ApiControlTypeConst
import com.itdct.onflow.system.api.global.ApiGlobalMap
import com.itdct.onflow.system.api.global.ApiRoleLock
import com.itdct.onflow.system.common.base.LoginDTO
import com.itdct.onflow.system.common.context.Context
import com.itdct.onflow.system.log.entity.SysApiLogEntity
import com.itdct.onflow.system.log.entity.SysImportantApiLogEntity
import com.itdct.onflow.system.log.global.SysApiLogList
import com.itdct.onflow.system.log.mapper.SysApiLogMapper
import com.itdct.onflow.system.log.mapper.SysImportantApiLogMapper
import org.aspectj.lang.annotation.Aspect
import org.springframework.stereotype.Component
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.*
import java.util.concurrent.ExecutorService

/**
 * @author Zhouwx
 * @date 2025/7/22 23:35:50
 * @version 1.0
 * @description
 */
@Aspect
@Component
class SysControllerAspect(
    onflowConfig: OnflowConfig,
    val redisUtil: RedisUtil,
    val sysApiLogMapper: SysApiLogMapper,
    val sysImportantApiLogMapper: SysImportantApiLogMapper,
    val logThreadPoolExecutor: ExecutorService,
    val redisReentrantLock: RedisReentrantLock
) : BaseControllerAspect<SysAccountEntity, LoginDTO>(onflowConfig) {

    override fun setContext(): BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>> {
        val context = Context()
        val sysApiLogEntity = SysApiLogEntity()
        sysApiLogEntity.requestTime = Date()
        sysApiLogEntity.instanceId = onflowConfig.instanceId
        sysApiLogEntity.platformType = onflowConfig.platformType
        context.sysApiLogEntity = sysApiLogEntity

        ContextHolder.setContext(context)
        return context as BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>
    }

    override fun initToken(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        val token = context.requestHeadMap["authorization"] ?: return
        val userInfoJson = redisUtil.get(SysAccountRedisKey.LOGIN_TOKEN(token)) as String?
        if (userInfoJson == null) {
            return
        }

        val loginDTO = JSON.parseObject(userInfoJson, LoginDTO::class.java)
        context.token = token
        context.loginDTO = loginDTO
        context.accountId = loginDTO.accountId
        context.accountName = loginDTO.accountName
        context.superAdmin = loginDTO.superAdmin

        if (context is Context) {
            context.sysApiLogEntity?.also {
                it.accountId = loginDTO.accountId
            }
        }

        // INFO: Zhouwx: 2025/9/28 刷新token存续时间
        refreshTokenExpireTime(context)
    }

    private fun refreshTokenExpireTime(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        val token = context.token ?: return
        val tryLock = redisReentrantLock.tryLock(SysAccountRedisKey.LOGIN_TOKEN_REFRESH_INTERVAL(token), 0, onflowConfig.login.tokenRefreshIntervalTime)
        if (tryLock) {
            // INFO: Zhouwx: 2025/9/28 如果获取到了Key，说明可以对Key进行续期操作
            redisUtil.expire(SysAccountRedisKey.LOGIN_TOKEN(token), onflowConfig.login.tokenValidTime)
        } else {
            // INFO: Zhouwx: 2025/9/28 说明Key还存在，不需要对token进行续期
        }
    }

    override fun afterInitContent(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        if (context is Context) {
            val key = "${context.request?.method?.uppercase()}://${context.requestUri}"
            val sysApiEntity = ApiGlobalMap.apiMap[key] ?: throw CommonException("未找到该接口")
            context.sysApiEntity = sysApiEntity

            context.sysApiLogEntity?.also {
                it.apiId = sysApiEntity.id!!
                it.url = sysApiEntity.url
                it.sourceIp = context.ipAddress
            }
        }
    }

    override fun checkApiEnable(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        if (context is Context) {
            val sysApiEntity = context.sysApiEntity ?: throw CommonException("未找到该接口")
            if (!sysApiEntity.enable) {
                throw CommonException("该接口已禁用")
            }
        }
    }

    override fun checkToken(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        if (context is Context) {
            val sysApiEntity = context.sysApiEntity ?: throw CommonException("未找到该接口")
            val controlType = sysApiEntity.controlType
            when (controlType) {
                ApiControlTypeConst.NOT_CONTROL -> {
                    // INFO: Zhouwx: 2025/9/5 不受任何权限控制
                    return
                }

                ApiControlTypeConst.LOGIN_CONTROL,
                ApiControlTypeConst.ROLE_CONTROL -> {
                    if (context.token == null) {
                        throw CommonException(ReturnCode.UNAUTHORIZED, CommonString.NEED_LOGIN)
                    }
                }

                else -> {
                    throw CommonException("未知权限控制类型")
                }
            }

        }
    }

    override fun checkApiPermission(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        if (context is Context) {
            if (context.superAdmin) {
                // INFO: Zhouwx: 2025/9/5 超管没有任何限制
                return
            }
            val sysApiEntity = context.sysApiEntity ?: throw CommonException("未找到该接口")

            when (sysApiEntity.controlType) {
                ApiControlTypeConst.LOGIN_CONTROL,
                ApiControlTypeConst.NOT_CONTROL -> {
                    // INFO: Zhouwx: 2025/9/5 不受控和登录受控不受接口权限控制
                    return
                }

                ApiControlTypeConst.ROLE_CONTROL -> {
                    // INFO: Zhouwx: 2025/9/5 角色控制，需要判断该角色是否拥有该api的权限
                    val loginDTO = context.loginDTO ?: throw CommonException("未查询到登录信息")
                    val roleId = loginDTO.roleId

                    var urls = ApiGlobalMap.roleApiMap[roleId]
                    if (urls == null) {
                        // INFO: Zhouwx: 2025/9/5 如果为空，需要判断角色api权限是否在刷新中，还有就是是否存在这个角色
                        if (ApiRoleLock.lock.isLocked) {
                            var retryTimes = 0
                            while (true) {
                                Thread.sleep(200)
                                if (!ApiRoleLock.lock.isLocked) {
                                    urls = ApiGlobalMap.roleApiMap[roleId]
                                    break
                                } else {
                                    retryTimes++
                                    if (retryTimes > 5) {
                                        throw CommonException("角色权限不存在")
                                    }
                                }
                            }
                        } else {
                            throw CommonException("角色权限不存在")
                        }
                    }
                    urls = urls ?: throw CommonException("角色权限不存在")
                    val apiKey = ApiGlobalMap.getApiKey(sysApiEntity)
                    if (!urls.contains(apiKey)) {
                        throw CommonException(ReturnCode.PERMISSION_FORBIDDEN, CommonString.PERMISSION_FORBIDDEN)
                    }
                }

                else -> {
                    throw CommonException("未知权限控制类型")
                }
            }
        }
    }

    override fun beforeRemoveContext(context: BaseContext<SysAccountEntity, BaseLoginDTO<SysAccountEntity>>) {
        if (context is Context) {
            context.sysApiLogEntity?.also {
                logThreadPoolExecutor.submit {
                    it.responseTime = Date()
                    val totalMs = it.responseTime?.time?.minus(it.requestTime?.time ?: 0) ?: 0
                    it.handleTime = BigDecimal(totalMs).divide(BigDecimal.valueOf(1000), 2, RoundingMode.HALF_UP)
                    it.returnCode = context.respVo?.code ?: ReturnCode.UNCAUGHT_SYSTEM_ERROR
                    it.failReason = if (it.returnCode == ReturnCode.SUCCESS) "" else context.respVo?.info ?: ""
                    SysApiLogList.add(it)

                    if (context.apiParamDTO.important) {
                        // INFO: Zhouwx: 2025/9/23 重要接口需要入库
                        val sysImportantApiLogEntity = SysImportantApiLogEntity()
                        KBeanCopyUtil.injectValue(it, sysImportantApiLogEntity, true)
                        sysImportantApiLogEntity.requestBody = context.requestBody
                        sysImportantApiLogEntity.responseBody = context.responseBody
                        sysImportantApiLogMapper.insertEx(sysImportantApiLogEntity)
                    }
                }
            }
        }
    }
}